#!/usr/bin/env python
# _*_ coding: UTF-8 _*_

import sys, os, re
import time

class Log:
    LGLEVEL_UNSET, \
    LGLEVEL_DEBUG, \
    LGLEVEL_INFO, \
    LGLEVEL_NOTICE, \
    LGLEVEL_WARNING, \
    LGLEVEL_ERROR, \
    LGLEVEL_FATAL = 0, 1, 2, 3, 4, 5, 6
    
    CS = \
    {
    LGLEVEL_UNSET:"UNSET",
    LGLEVEL_DEBUG:"DEBUG",
    LGLEVEL_INFO:"INFO",
    LGLEVEL_NOTICE:"NOTICE",
    LGLEVEL_WARNING:"WARNING",
    LGLEVEL_ERROR:"ERROR",
    LGLEVEL_FATAL:"FATAL"
    }

    def __init__(self, fhandle = sys.stdout):
        self.fhandle = fhandle
        self.termctl = Log.TerminalController(fhandle)
    
    def format(self, level, *message):
        strtime = time.strftime("%Y-%m-%d %H:%M:%S")
        messages = ""
        for mentry in message:
            messages = messages + " " + mentry
        messages = messages.strip()
        
        if level == Log.LGLEVEL_UNSET:
            messages = "%s %s\n" % (strtime, messages)
        elif level == None:
            messages = "%s\n" % (messages,)
        else:
            messages = "%s %s %s\n" % (strtime, Log.CS[level], messages)

        return messages
    
    def log(self, level, *message):
        self.fhandle.write(self.format(level, *message))

    def fileno(self):
        return self.fhandle.fileno()

    def write(self, message):
        os.write(self.fhandle.fileno(), message)
    
    def writef(self, message, ret = False):
        message = self.termctl.render(message)
        if ret:
            return message
        self.write(message)

    class TerminalController:
        """
        Controlling terminal format
        
        See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 
        """
        
        BOL = ''             #: Move the cursor to the beginning of the line
        UP = ''              #: Move the cursor up one line
        DOWN = ''            #: Move the cursor down one line
        LEFT = ''            #: Move the cursor left one char
        RIGHT = ''           #: Move the cursor right one char
        CLEAR_SCREEN = ''    #: Clear the screen and move to home position
        CLEAR_EOL = ''       #: Clear to the end of the line.
        CLEAR_BOL = ''       #: Clear to the beginning of the line.
        CLEAR_EOS = ''       #: Clear to the end of the screen
        BOLD = ''            #: Turn on bold mode
        BLINK = ''           #: Turn on blink mode
        DIM = ''             #: Turn on half-bright mode
        REVERSE = ''         #: Turn on reverse-video mode
        NORMAL = ''          #: Turn off all modes
        HIDE_CURSOR = ''     #: Make the cursor invisible
        SHOW_CURSOR = ''     #: Make the cursor visible
        
        COLS = None          #: Width of the terminal (None for unknown)
        LINES = None         #: Height of the terminal (None for unknown)
    
        TERMCAPS = """BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
        CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
        BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
        HIDE_CURSOR=civis SHOW_CURSOR=cnorm"""
    
        def __init__(self, term = sys.stdout):
            try: import curses
            except: return
    
            if not hasattr(term, 'isatty') or not term.isatty(): 
                return
    
            try: curses.setupterm()
            except: return
    
            for cap in self.TERMCAPS.split():
                (attrib, cap_name) = cap.split('=')
                setattr(self, attrib, self._tigetstr(cap_name) or '')

            self.COLS = curses.tigetnum('cols')
            self.LINES = curses.tigetnum('lines')

        def render(self, template):
            return re.sub(r'\$\$|\${\w+}', self._render_sub, template)

        def _render_sub(self, match):
            s = match.group()
            if s == '$$': return s
            else: return getattr(self, s[2:-1])

        def _tigetstr(self, cap_name):
            import curses
            cap = curses.tigetstr(cap_name) or ''
            return re.sub(r'\$<\d+>[/*]?', '', cap)
